//@author A0100976E
package tasky.logic;

import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.joda.time.DateTime;
import org.joda.time.DateTimeComparator;
import org.joda.time.Interval;

import tasky.commons.Task;
import tasky.history.History;
import tasky.storage.Storage;

public class EditCommand implements Command {


	
	
	private ArrayList<Task> tasks;
	private AddParser addParser;
	private Storage storage;
	private History history;
	private Logger logger;
	private String data;
	private String errorMessage;
	String warningMessage;
	private String output;
	private boolean isError;
	private boolean warning = false;
	private static final String EDIT_SUCCESSFUL = "Task edited successfully\n";
	private static final String INVALID_ID = "Task index is invalid\n";
	private static final String EMPTY_TASK_CONTENT = "";
	private static final String ERRORMSG_EMPTY_TASK_CONTENT = "Empty task content entered.\n";
	private static final String WARNING_MSG_DEADLINE_EXPIRED = "deadline is before current date!\n";
	private static final String WARNING_MSG_END_DATE_EXPIRED = "End date is before current date!\n";
	private static final String WARNINGMSG_OVERLAPTASK_HEADER = "%s collides with:\n";
	private static final String WARNINGMSG_OVERLAPTASK = "%d. %s\n";
	private static final String COMMAND_EDIT = "edit";
	private static final int BASEINDEX = 1;
	private static final int INVALID_INDEX = -1;
	private static final String SPACING = " ";
	private static final String EMPTY = "";
	public EditCommand(ArrayList<Task> tasks, Storage storage, History history,
			Logger logger, boolean isEditing) {
		this.tasks = tasks;
		this.addParser = new AddParser();
		this.storage = storage;
		this.history = history;
		this.logger = logger;
		errorMessage = EMPTY;
	}

	@Override
	public void acceptInput(String data) {
		this.data = data;

	}

	@Override
	public void execute() {
		isError = false;
		int id = INVALID_INDEX;
		Task modifiedTask = null;

		try {
			id = getTaskID(data);
		} catch (IllegalArgumentException e) {
			errorMessage = e.getMessage();
			isError = true;
		}
		if (!isError&&isIDValid(id)) {
			id = id - BASEINDEX;
			data = getTaskContent(data);
			try {
				modifiedTask = addParser.parse(data, tasks);
			} catch (ParseException e) {
				errorMessage = e.getMessage();
				isError = true;
				logger.log(Level.INFO, errorMessage);
			}
			if (modifiedTask == null) {
				isError = true;
			} else if (modifiedTask.getContent().equals(EMPTY_TASK_CONTENT)) {
				errorMessage = ERRORMSG_EMPTY_TASK_CONTENT;
				isError = true;
			} else {
				history.storeUndo(tasks, COMMAND_EDIT);
				tasks.set(id, modifiedTask);
			}
			output = EDIT_SUCCESSFUL;
		} else {
			isError = true;
			errorMessage = INVALID_ID;
		}
		if (!isError) {
			checkExpiredDate(modifiedTask);
			checkInterval(modifiedTask);
		}
	}

	@Override
	public String save() throws IOException {
		return storage.writeToStorage(tasks);
	}

	@Override
	public String outputToUser() {
		if (isError) {
			output = errorMessage;
		}
		return output;
	}

	// check if the original ID given by the user is valid. NOTE: ID is not
	// adjusted to base 0 of ArrayList
	private boolean isIDValid(int id) {

		if (tasks.size() >= 1) {
			if (id >= 1 && id <= tasks.size()) {
				return true;
			}
		}
		return false;
	}

	private int getTaskID(String data) throws IllegalArgumentException {
		try {
			int k = Integer.valueOf(obtainFirstWord(data));
			return k;
		} catch (Exception e) {
			throw new IllegalArgumentException(INVALID_ID);
		}
	}

	private String obtainFirstWord(String sentence) {

		String[] words;
		String trimmedSentence;
		trimmedSentence = sentence.trim();

		words = trimmedSentence.split(SPACING);

		return words[0];

	}

	private String getTaskContent(String data) {
		return omitFirstWord(data);
	}

	private String omitFirstWord(String sentence) {

		String[] words;
		String trimmedSentence;
		trimmedSentence = sentence.trim();

		words = trimmedSentence.split(SPACING, 2);
		if (words.length == 2) {
			return words[1];
		} else {
			return EMPTY;
		}

	}

	@Override
	public boolean isError() {
		return isError;
	}
	public void checkExpiredDate(Task newTask) {
		DateTime todayDate = new DateTime();
		DateTimeComparator compareDate = DateTimeComparator
				.getDateOnlyInstance();
		if (newTask.getDeadline() != null
				&& (compareDate.compare(newTask.getDeadline(), todayDate) < 0)) {

			warningMessage = WARNING_MSG_DEADLINE_EXPIRED;
			warning = true;

		} else if (newTask.getEnd() != null) {
			if (newTask.getEnd() != null
					&& (compareDate.compare(newTask.getEnd(), todayDate) < 0)) {
				warningMessage = WARNING_MSG_END_DATE_EXPIRED;
				warning = true;
			}
		}
	}

	private void checkInterval(Task newTask) {
		boolean overlapExists = false;
		Interval newTaskInterval, taskInterval;
		StringBuilder overlappingTask = new StringBuilder();
		overlappingTask.append(String.format(WARNINGMSG_OVERLAPTASK_HEADER,
				newTask.getContent()));

		if (containsInterval(newTask)) {
			newTaskInterval = obtainInterval(newTask);
			for (Task task : tasks) {
				taskInterval = obtainInterval(task);
				if (task != newTask && newTaskInterval.overlaps(taskInterval)) {
					overlappingTask.append(String.format(WARNINGMSG_OVERLAPTASK,
							task.getId(),task.getContent()));
					overlapExists = true;
				}
			}
			if (overlapExists) {
				warningMessage = overlappingTask.toString();
				warning = true;
			}
		}
	}

	private boolean containsInterval(Task newTask) {

		DateTime startDate = newTask.getStart();
		DateTime endDate = newTask.getEnd();

		if (startDate != null && endDate != null) {
			return true;
		} else {
			return false;
		}

	}

	private Interval obtainInterval(Task newTask) {
		Interval taskInterval = new Interval(newTask.getStart(),
				newTask.getEnd());
		return taskInterval;
	}

	public boolean getWarning() {
		return warning;
	}

	public String getWarningMessage() {
		return warningMessage;
	}

}
